package com.googlecode.openrtp.spi.rtcp;

import com.googlecode.openrtp.spi.rtcp.RtcpHeaderPacket;
import java.util.Collections;
import java.util.Map;

/**
 *
 *            0                   1                   2                   3
 *          0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * header |V=2|P|    RC   |   PT=SR=200   |             length            |
 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *        |                         SSRC of sender                        |
 *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
 * sender |              NTP timestamp, most significant word             |
 * info   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *        |             NTP timestamp, least significant word             |
 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *        |                         RTP timestamp                         |
 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *        |                     sender's packet count                     |
 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *        |                      sender's octet count                     |
 *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
 * report |                 SSRC_1 (SSRC of first source)                 |
 * block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *   1    | fraction lost |       cumulative number of packets lost       |
 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *        |           extended highest sequence number received           |
 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *        |                      interarrival jitter                      |
 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *        |                         last SR (LSR)                         |
 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *        |                   delay since last SR (DLSR)                  |
 *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
 * report |                 SSRC_2 (SSRC of second source)                |
 * block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *   2    :                               ...                             :
 *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
 *        |                  profile-specific extensions                  |
 *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * 
 * @author jocke
 */
public class RtcpSenderPacket implements RtcpPacket {

    
    private RtcpHeaderPacket headerPacket;
    
    
    /**
     * SSRC: 32 bits The synchronization source identifier for the originator of
     * this SR packet.
     */
    private long ssrc;
    
    /**
     * NTP timestamp: 64 bits Indicates the wallclock time when this report was
     * sent so that it may be used in combination with timestamps returned in
     * reception reports from other receivers to measure round-trip propagation
     * to those receivers. Receivers should expect that the measurement accuracy
     * of the timestamp may be limited to far less than the resolution of the
     * NTP timestamp. The measurement uncertainty of the timestamp is not
     * indicated as it may not be known. A sender that can keep track of elapsed
     * time but has no notion of wallclock time may use the elapsed time since
     * joining the session instead. This is assumed to be less than 68 years, so
     * the high bit will be zero. It is permissible to use the sampling clock to
     * estimate elapsed wallclock time. A sender that has no notion of wallclock
     * or elapsed time may set the NTP timestamp to zero.
     */
    private long ntp;
    /**
     * RTP timestamp: 32 bits Corresponds to the same time as the NTP timestamp
     * (above), but in the same units and with the same random offset as the RTP
     * timestamps in data packets. This correspondence may be used for intra-
     * and inter-media synchronization for sources whose NTP timestamps are
     * synchronized, and may be used by media- independent receivers to estimate
     * the nominal RTP clock frequency. Note that in most cases this timestamp
     * will not be equal to the RTP timestamp in any adjacent data packet.
     * Rather, it is calculated from the corresponding NTP timestamp using the
     * relationship between the RTP timestamp counter and real time as
     * maintained by periodically checking the wallclock time at a sampling
     * instant.
     */
    private int rtpTimestamp;
    /**
     * sender's packet count: 32 bits The total number of RTP data packets
     * transmitted by the sender since starting transmission up until the time
     * this SR packet was generated. The count is reset if the sender changes
     * its SSRC identifier.
     *
     */
    private int senderPacketCount;
    /**
     * sender's octet count: 32 bits The total number of payload octets (i.e.,
     * not including header or padding) transmitted in RTP data packets by the
     * sender since starting transmission up until the time this SR packet was
     * generated. The count is reset if the sender changes its SSRC identifier.
     * This field can be used to estimate the average payload data rate.
     */
    private int senderOctetCount;
    
    private Map<Long, ReceiverReportBlock> blocks;

    private RtcpSenderPacket(RtcpHeaderPacket headerPacket,long ssrc,  long ntp, int rtpTimestamp, int senderPacketCount, int senderOctetCount, Map<Long, ReceiverReportBlock> blocks) {
        this.headerPacket = headerPacket;
        this.ntp = ntp;
        this.rtpTimestamp = rtpTimestamp;
        this.senderPacketCount = senderPacketCount;
        this.senderOctetCount = senderOctetCount;
        this.blocks = blocks;
    }

    public static RtcpSenderPacket create(RtcpHeaderPacket headerPacket, long ssrc, long ntp, int rtpTimestamp, int senderPacketCount, int senderOctetCount, Map<Long, ReceiverReportBlock> blocks) {
        return new RtcpSenderPacket(headerPacket,ssrc, ntp, rtpTimestamp, senderPacketCount, senderOctetCount, blocks);
    }

    public RtcpHeaderPacket getHeaderPacket() {
        return headerPacket;
    }

    public long getNtp() {
        return ntp;
    }

    public int getRtpTimestamp() {
        return rtpTimestamp;
    }

    public int getSenderPacketCount() {
        return senderPacketCount;
    }

    public int getSenderOctetCount() {
        return senderOctetCount;
    }

    public Map<Long, ReceiverReportBlock> getBlocks() {
        return Collections.unmodifiableMap(blocks);
    }
    
    
    public static final class ReceiverReportBlock {

        public ReceiverReportBlock(long ssrcN, int fractionLost, int cumulativePacketLost, int highestSequenceNumber, int interarrivalJitter, int lsr, int dlsr) {
            this.ssrcN = ssrcN;
            this.fractionLost = fractionLost;
            this.cumulativePacketLost = cumulativePacketLost;
            this.highestSequenceNumber = highestSequenceNumber;
            this.interarrivalJitter = interarrivalJitter;
            this.lsr = lsr;
            this.dlsr = dlsr;
        }
        
        
        public static ReceiverReportBlock create(long ssrcN, int fractionLost, int cumulativePacketLost, int highestSequenceNumber, int interarrivalJitter, int lsr, int dlsr) {
            return new ReceiverReportBlock(ssrcN, fractionLost, cumulativePacketLost, highestSequenceNumber, interarrivalJitter, lsr, dlsr);
        }
        

        /**
         * SSRC_n (source identifier): 32 bits The SSRC identifier of the source
         * to which the information in this reception report block pertains.
         */
        private long ssrcN;
        /**
         * fraction lost: 8 bits The fraction of RTP data packets from source
         * SSRC_n lost since the previous SR or RR packet was sent, expressed as
         * a fixed point number with the binary point at the left edge of the
         * field. (That is equivalent to taking the integer part after
         * multiplying the loss fraction by 256.) This fraction is defined to be
         * the number of packets lost divided by the number of packets expected,
         * as defined in the next paragraph. An implementation is shown in
         * Appendix A.3. If the loss is negative due to duplicates, the fraction
         * lost is set to zero. Note that a receiver cannot tell whether any
         * packets were lost after the last one received, and that there will be
         * no reception report block issued for a source if all packets from
         * that source sent during the last reporting interval have been lost.
         */
        private int fractionLost;
        /**
         * cumulative number of packets lost: 24 bits The total number of RTP
         * data packets from source SSRC_n that have been lost since the
         * beginning of reception. This number is defined to be the number of
         * packets expected less the number of packets actually received, where
         * the number of packets received includes any which are late or
         * duplicates. Thus packets that arrive late are not counted as lost,
         * and the loss may be negative if there are duplicates. The number of
         * packets expected is defined to be the extended last sequence number
         * received, as defined next, less the initial sequence number received.
         * This may be calculated as shown in Appendix A.3.
         */
        private int cumulativePacketLost;
        /**
         * extended highest sequence number received: 32 bits The low 16 bits
         * contain the highest sequence number received in an RTP data packet
         * from source SSRC_n, and the most significant 16 bits extend that
         * sequence number with the corresponding count of sequence number
         * cycles, which may be maintained according to the algorithm in
         * Appendix A.1. Note that different receivers within the same session
         * will generate different extensions to the sequence number if their
         * start times differ significantly.
         */
        private int highestSequenceNumber;
        /**
         * interarrival jitter: 32 bits An estimate of the statistical variance
         * of the RTP data packet interarrival time, measured in timestamp units
         * and expressed as an unsigned integer. The interarrival jitter J is
         * defined to be the mean deviation (smoothed absolute value) of the
         * difference D in packet spacing at the receiver compared to the sender
         * for a pair of packets. As shown in the equation below, this is
         * equivalent to the difference in the "relative transit time" for the
         * two packets; the relative transit time is the difference between a
         * packet's RTP timestamp and the receiver's clock at the time of
         * arrival, measured in the same units. If Si is the RTP timestamp from
         * packet i, and Ri is the time of arrival in RTP timestamp units for
         * packet i, then for two packets i and j, D may be expressed as
         *
         * D(i,j)=(Rj-Ri)-(Sj-Si)=(Rj-Sj)-(Ri-Si)
         */
        private int interarrivalJitter;
        /**
         * last SR timestamp (LSR): 32 bits The middle 32 bits out of 64 in the
         * NTP timestamp (as explained in Section 4) received as part of the
         * most recent RTCP sender report (SR) packet from source SSRC_n. If no
         * SR has been received yet, the field is set to zero.
         */
        private int lsr;
        /**
         * delay since last SR (DLSR): 32 bits The delay, expressed in units of
         * 1/65536 seconds, between receiving the last SR packet from source
         * SSRC_n and sending this reception report block. If no SR packet has
         * been received yet from SSRC_n, the DLSR field is set to zero.
         */
        private int dlsr;

        public long getSsrcN() {
            return ssrcN;
        }

        public int getFractionLost() {
            return fractionLost;
        }

        public int getCumulativePacketLost() {
            return cumulativePacketLost;
        }

        public int getHighestSequenceNumber() {
            return highestSequenceNumber;
        }

        public int getInterarrivalJitter() {
            return interarrivalJitter;
        }

        public int getLsr() {
            return lsr;
        }

        public int getDlsr() {
            return dlsr;
        }
    }

    @Override
    public String toString() {
         return "RtcpSenderPacket{" + "headerPacket=" + headerPacket + ", ntp=" + ntp + ", rtpTimestamp=" + rtpTimestamp + ", senderPacketCount=" + senderPacketCount + ", senderOctetCount=" + senderOctetCount + '}';
    }
}
